本文同步更新於blog
情境:這是公司生產的文字積木
<?php
namespace App\Flyweight\Blocks;
class ConcreteBlock
{
/**
* @var string
*/
protected $shape;
/**
* @var string
*/
public $word;
/**
* @param string $shape
* @param string $word
*/
public function __construct(string $shape, string $word)
{
$this->shape = $shape;
$this->word = $word;
}
/**
* @return string
*/
public function getShape(): string
{
return $this->shape;
}
/**
* @return string
*/
public function getWord(): string
{
return $this->word;
}
}
namespace App\Flyweight\Blocks;
<?php
namespace App\Flyweight\Blocks;
use App\Flyweight\Blocks\ConcreteBlock;
class Program
{
/**
* @return array
*/
public function getBlocks(): array
{
$firstBlock = new ConcreteBlock('star', 'B');
$secondBlock = new ConcreteBlock('square', 'E');
$thirdBlock = new ConcreteBlock('square', 'A');
$fourthBlock = new ConcreteBlock('square', 'R');
return [$firstBlock, $secondBlock, $thirdBlock, $fourthBlock];
}
}
隨著積木越賣越好,我們會創建出許多Block,
它們要顯示的文字各不相同,但形狀大概就那幾種。
我們決定改變積木的實作,不紀錄顯示文字於積木的狀態中。
抽離出共用的形狀部分,來節省記憶體的消耗。
<?php
namespace App\Flyweight\Blocks\Contracts;
interface Block
{
public function getShape();
public function display(string $word): string;
}
之後我們要顯示文字時,會使用display()方法。
<?php
namespace App\Flyweight\Blocks;
use App\Flyweight\Blocks\Contracts\Block;
class ConcreteBlock implements Block
{
/**
* @var string
*/
protected $shape;
/**
* @param string $shape
*/
public function __construct(string $shape)
{
$this->shape = $shape;
}
/**
* @return string
*/
public function getShape(): string
{
return $this->shape;
}
/**
* @param string $word
* @return string
*/
public function display(string $word): string
{
return $word;
}
}
<?php
namespace App\Flyweight\Blocks;
use App\Flyweight\Blocks\ConcreteBlock;
use App\Flyweight\Blocks\Contracts\Block;
class BlockFactory
{
/**
* @var Block[]
*/
protected $blocks;
/**
* @param string $shape
* @return ConcreteBlock
*/
public function getBlock(string $shape): Block
{
if (!isset($this->blocks[$shape])) {
$this->blocks[$shape] = new ConcreteBlock($shape);
}
return $this->blocks[$shape];
}
}
<?php
namespace App\Flyweight\Blocks;
use App\Flyweight\Blocks\Block;
class Program
{
/**
* @return array
*/
public function getBlocks(): array
{
$blockFactory = new BlockFactory();
$firstBlock = $blockFactory->getBlock('star');
// $firstBlock->display('B');
$secondBlock = $blockFactory->getBlock('square');
// $secondBlock->display('E');
$thirdBlock = $blockFactory->getBlock('square');
// $thirdBlock->display('A');
$fourthBlock = $blockFactory->getBlock('square');
// $fourthBlock->display('R');
return [$firstBlock, $secondBlock, $thirdBlock, $fourthBlock];
}
}
當客戶端要顯示文字時,再呼叫display()方法。
[單一職責原則]
我們將管理內部狀態與管理外部狀態,視為兩種不同的職責。
透過區分兩者,我們便可以用 簡單工廠模式 搭配 單例模式,
切出細粒度的物件,來共用相同的程式碼。
其蠅量類別只紀錄內部狀態且創建後便不會改變。
[開放封閉原則]
透過工廠,我們可以修改積木本身的實作(例如換廠牌),而不影響客戶端。
當客戶端修改外部狀態時,也不影響原本純內部狀態的積木。
[裡氏替換原則]
工廠依賴於抽象的積木介面。
實體積木實作了抽象的積木介面。
最後附上類別圖:
(註:若不熟悉 UML 類別圖,可參考UML類別圖說明。)
ʕ •ᴥ•ʔ:原來共享經濟是用了蠅量模式的概念啊。